﻿using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using NDasm.Core.UI.Base;
using Mono.Cecil;
using Mono.Cecil.Cil;

namespace NDasm.Core.UI.MethodDasm
{
    public class MethodDasmViewModel : ViewModel
    {
        private readonly MethodDefinition method;

        public MethodDasmViewModel(MethodDefinition method)
        {
            this.method = method;
            Instructions = new ObservableCollection<InstructionViewModel>();
            FillInstructions();
            GoToCommand = new DelegateCommand<int>(GoToOffset);
        }        

        public ObservableCollection<InstructionViewModel> Instructions { get; private set; }

        public string MethodName
        {
            get { return string.Format("{0}.{1}", method.DeclaringType.FullName, method.Name); }
        }

        public string FullMethodName
        {
            get { return method.FullName; }
        }

        private bool showNops = true;
        public bool ShowNops
        {
            get { return showNops; }
            set
            {
                showNops = value;
                FillInstructions();
                NotifyPropertyChanged(() => ShowNops);
            }
        }

        private bool simpleMethodNames = true;
        public bool SimpleMethodNames
        {
            get { return simpleMethodNames; }
            set
            {
                simpleMethodNames = value;
                foreach (var instruction in Instructions)
                    instruction.SimpleMethodName = value;
                NotifyPropertyChanged(() => SimpleMethodNames);
            }
        }

        private InstructionViewModel selectedInstruction;
        public InstructionViewModel SelectedInstruction
        {
            get { return selectedInstruction; }
            set
            {
                selectedInstruction = value;
                NotifyPropertyChanged(() => SelectedInstruction);
            }
        }

        public ICommand GoToCommand { get; private set; }

        private void FillInstructions()
        {
            Instructions.Clear();
            foreach (Instruction instruction in method.Body.Instructions)
            {
                if (!ShowNops && instruction.OpCode.Code == Code.Nop)
                    continue;
                Instructions.Add(new InstructionViewModel(instruction) {SimpleMethodName = SimpleMethodNames});
            }
        }

        private void GoToOffset(int offset)
        {
            SelectedInstruction = Instructions.FirstOrDefault(i => i.RawOffset >= offset);
        }
    }
}
